/**
 * **************** Copyright (C) *****************
 * <p/>
 * Version       Date            Author
 * ─────────────────────────────────────
 * V1.0        2017/6/17         yellowlgx
 * <p/>
 * **************** End of Head *******************
 */
package android.support.v7.widget;

import android.content.Context;
import android.os.SystemClock;
import android.view.FocusFinder;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;

import com.skyworth.theme.widget.IThemeable;
import com.skyworth.ui.newrecycleview.NewRecycleViewHolder;
import com.skyworth.ui.newrecycleview.OnScrollStateListener;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @author : yellowlgx
 * @ClassName NewRecyclerView
 * @Description : TODO
 * @date : 2017/6/17 14:37
 */
public class NewRecyclerView extends RecyclerView implements IThemeable
{
    private static final String TAG = "NewRecyclerView";
    private NewRecycleAdapter mAdapter;
    private LinearLayoutManager mLayoutManager;
    private boolean mDropKey = false;
    private static final int DROP_TIME = 300;
    private long mLastTime = 0;
    private int mSpanCount = 1;

    private OnScrollStateListener mListener;

    private int nextFocusPosition = -1;

    public NewRecyclerView(Context context)
    {
        super(context);
        setNestedScrollingEnabled(true);
        setHasFixedSize(true);
        setFocusable(false);
        setFocusableInTouchMode(false);
        setChildDrawingOrderCallback(drawingOrderCallback);
        setOverScrollMode(OVER_SCROLL_NEVER);
        setItemAnimator(null);//去除Item加载动画，解决由于刷新导致的焦点混乱问题
    }

    public void setSpanCount(int count)
    {
        mSpanCount = count;
    }

    public void setOnScrolledListener(OnScrollStateListener listener)
    {
        mListener = listener;
    }

    public void dropKeyOneTime()
    {
        mDropKey = true;
        mLastTime = SystemClock.uptimeMillis();
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event)
    {
        if (mDropKey && (SystemClock.uptimeMillis() - mLastTime) > DROP_TIME)
        {
            mDropKey = false;
        }
        if (mDropKey)
        {
            return true;
        }

        if (event.getAction() == KeyEvent.ACTION_DOWN)
        {
            if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN || event.getKeyCode() == KeyEvent
                    .KEYCODE_DPAD_UP)
            {
                this.post(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        View view = mLayoutManager.getFocusedChild();
                        if (view != null)
                        {
                            RecyclerView.LayoutParams p = (LayoutParams) view.getLayoutParams();
                            int selectPosition = p.getViewLayoutPosition();
                            if (mListener != null)
                                mListener.onScrollby(selectPosition);
                        }
                    }
                });
            }
        }
        return super.dispatchKeyEvent(event);
    }

    /**
     * @param position
     * @return int
     * @Description 获取当前位置所在列数<br/>
     */
    public int getCol(int position)
    {
//        if (mLayoutManager != null && mLayoutManager.getOrientation() == OrientationHelper.HORIZONTAL)
//        {
        int temp = (position + 1) / mSpanCount;
        int mode = (position + 1) % mSpanCount;
        if (mode != 0)
        {
            temp++;
        }
        return temp;
//        }
//        return 0;
    }

    /**
     * @param position
     * @return int
     * @Description 获取当前位置所在行数<br/>
     */
    public int getRow(int position)
    {
//        if (mLayoutManager != null && mLayoutManager.getOrientation() == OrientationHelper.VERTICAL)
//        {
        int temp = (position + 1) / mSpanCount;
        int mode = (position + 1) % mSpanCount;
        if (mode != 0)
        {
            temp++;
        }
        return temp;
//        }
//        return 0;
    }

    /**
     * @param position
     * @return int
     * @Description 判断当前位置是否是最后一列<br/>
     */
    public boolean isLastCol(int position)
    {
        if (mLayoutManager.getOrientation() == OrientationHelper.VERTICAL)
        {
            if ((position + 1) % mSpanCount == 0 || position == (getAdapter().getItemCount()-1))
                return true;
        } else
        {
            if (getCol(position) == getCol(getAdapter().getItemCount() - 1))
                return true;
        }
        return false;
    }

    /**
     * @param position
     * @return int
     * @Description 判断当前位置是否是第一列<br/>
     */
    public boolean isFirstCol(int position)
    {
        if (mLayoutManager.getOrientation() == OrientationHelper.VERTICAL)
        {
            if (position % mSpanCount == 0)
                return true;
        } else
        {
            if (position < mSpanCount)
                return true;
        }
        return false;
    }

    /**
     * @param position
     * @return int
     * @Description 判断当前位置是否是最后一行<br/>
     */
    public boolean isLastRow(int position)
    {
        if (mLayoutManager.getOrientation() == OrientationHelper.VERTICAL)
        {
            if (getRow(position) == getRow(getAdapter().getItemCount() - 1))
                return true;
        } else
        {
            if ((position + 1) % mSpanCount == 0)
                return true;
        }
        return false;
    }

    /**
     * @param position
     * @return int
     * @Description 判断当前位置是否是第一行<br/>
     */
    public boolean isFirstRow(int position)
    {
        if (mLayoutManager.getOrientation() == OrientationHelper.VERTICAL)
        {
            if (position < mSpanCount)
                return true;
        } else
        {
            if (position % mSpanCount == 0)
                return true;
        }
        return false;
    }

    @Override

    protected void onAttachedToWindow()
    {
        super.onAttachedToWindow();
        addOnScrollListener(scrollListener);
    }

    @Override
    protected void onDetachedFromWindow()
    {
        super.onDetachedFromWindow();
        removeOnScrollListener(scrollListener);
    }

    @Override
    public void setAdapter(Adapter adapter)
    {
        super.setAdapter(adapter);
        mAdapter = (NewRecycleAdapter) adapter;
        refreshCurViewHolder(true);
        reset();
    }

    public void reset() {
        nextFocusPosition = -1;
    }

    public void refreshCurViewHolder(final boolean needCallback)
    {
        this.post(new Runnable()
        {
            @Override
            public void run()
            {
                if (NewRecyclerView.this.getAdapter() == null)
                    return;
                int first = mLayoutManager.findFirstVisibleItemPosition();
                int last = mLayoutManager.findLastVisibleItemPosition();
                if (mListener != null && needCallback)
                    mListener.onScrollEnd(NewRecyclerView.this, first, last);
                for (int i = first; i <= last; i++)
                {
                    NewRecycleViewHolder holder = (NewRecycleViewHolder)
                            findViewHolderForAdapterPosition(i);
                    if (holder != null)
                    {
                        holder.refreshUI();
                    }
                }
//                List<NewRecycleViewHolder> holders = ((NewRecycleAdapter) NewRecyclerView.this.getAdapter())
//                        .getViewHolders();
//                for (NewRecycleViewHolder holder : holders)
//                {
//                    if (holder != null)
//                        holder.refreshUI();
//                }
            }
        });
    }

    @Override
    public void setLayoutManager(LayoutManager layout)
    {
        super.setLayoutManager(layout);
//        if (layout instanceof NewLayoutManager)
//            mLayoutManager = (NewLayoutManager) layout;
        mLayoutManager = (LinearLayoutManager) layout;
    }

    @Override
    public View focusSearch(View focused, int direction)
    {
        if(mSpanCount == 1) {
            View result = getLayoutManager().onInterceptFocusSearch(focused, direction);
            if (result != null)
            {
                return result;
            }
            final FocusFinder ff = FocusFinder.getInstance();
            result = ff.findNextFocus(this, focused, direction);
            int focusPosition = getChildLayoutPosition(focused);
            if (direction == View.FOCUS_DOWN && result != null)
            {
                int resultPosition = getChildLayoutPosition(result);
                if(mLayoutManager.getOrientation() == OrientationHelper.VERTICAL) {
                    if (getRow(focusPosition) == getRow(resultPosition))
                        result = null;
                }else if(mLayoutManager.getOrientation() == OrientationHelper.HORIZONTAL) {
                    if (getCol(focusPosition) == getCol(resultPosition))
                        result = null;
                }
            }
            if (result == null && getAdapter() != null && getLayoutManager() != null && !isComputingLayout()
                    && !isLayoutFrozen())
            {
                eatRequestLayout();
                result = getLayoutManager().onFocusSearchFailed(focused, direction, mRecycler, mState);
                resumeRequestLayout(false);
            }
            if (result != null && result.getWidth() != 0)
            {
                return result;
            }
            if (mLayoutManager.getOrientation() != OrientationHelper.HORIZONTAL &&
                    (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP))
            {
                if (focused != null && focused.getWidth() != 0)
                {
                    dropKeyOneTime();
                    return focused;
                }
            }

            if (result == null)
            {
                result = super.focusSearch(focused, direction);
            }

            return result;
        } else {

            int focusPosition = getChildLayoutPosition(focused);
            if(nextFocusPosition != -1 && nextFocusPosition != focusPosition && direction == View.FOCUS_DOWN) {
                View curFocusView = mLayoutManager.findViewByPosition(nextFocusPosition);
                if(curFocusView != null) {
                    focusPosition = nextFocusPosition;
                    focused = curFocusView;
                    if(!focused.hasFocus())
                        focused.requestFocus();
                } else {
                    dropKeyOneTime();
                    return null;
                }
            }

            View result = getLayoutManager().onInterceptFocusSearch(focused, direction);
            if (result != null)
            {
                if(direction == View.FOCUS_DOWN)
                    nextFocusPosition = getChildLayoutPosition(result);
                else
                    nextFocusPosition = -1;
                return result;
            }
            final FocusFinder ff = FocusFinder.getInstance();
            result = ff.findNextFocus(this, focused, direction);
            if (direction == View.FOCUS_DOWN && result != null)
            {
                int resultPosition = getChildLayoutPosition(result);
                if(mLayoutManager.getOrientation() == OrientationHelper.VERTICAL) {
                    if (getRow(focusPosition) == getRow(resultPosition))
                        result = null;
                }else if(mLayoutManager.getOrientation() == OrientationHelper.HORIZONTAL) {
                    if (getCol(focusPosition) == getCol(resultPosition))
                        result = null;
                }
            }
            if (result == null && getAdapter() != null && getLayoutManager() != null && !isComputingLayout()
                    && !isLayoutFrozen())
            {
                eatRequestLayout();
                RecyclerView.LayoutParams focusParams = (RecyclerView.LayoutParams)focused.getLayoutParams();
                if(focusParams != null) {
                    if(focusParams.mViewHolder.mPosition != focusPosition) {
                        dropKeyOneTime();
                        return focused;
                    }
                }
                result = getLayoutManager().onFocusSearchFailed(focused, direction, mRecycler, mState);
                resumeRequestLayout(false);
                dropKeyOneTime();
            }
            if (result != null && result.getWidth() != 0)
            {
                if(direction == View.FOCUS_DOWN)
                    nextFocusPosition = getChildLayoutPosition(result);
                else
                    nextFocusPosition = -1;
                return result;
            }
            if (mLayoutManager.getOrientation() != OrientationHelper.HORIZONTAL &&
                    (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP))
            {
                if (focused != null && focused.getWidth() != 0)
                {
                    dropKeyOneTime();
                    return focused;
                }
            }

            if (result == null)
            {
                result = super.focusSearch(focused, direction);
            }

            return result;
        }
    }

    RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener()
    {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState)
        {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == RecyclerView.SCROLL_STATE_IDLE)
            {
                int first = mLayoutManager.findFirstVisibleItemPosition();
                int last = mLayoutManager.findLastVisibleItemPosition();
                if (mListener != null)
                    mListener.onScrollEnd(NewRecyclerView.this, first, last);
//                for (int i = first; i <= last; i++)
//                {
//                    NewRecycleViewHolder holder = (NewRecycleViewHolder)
//                            findViewHolderForAdapterPosition(i);
//                    if (holder != null)
//                    {
//                        holder.refreshUI();
//                    }
//                }
                if (mAdapter != null)
                    for (int i = 0; i < mAdapter.getViewHolders().size(); i++)
                    {
                        NewRecycleViewHolder holder = (NewRecycleViewHolder) mAdapter.getViewHolders().get(i);
                        if (holder != null)
                        {
                            holder.refreshUI();
                        }
                    }
            } else
            {
                if (mListener != null)
                    mListener.onScrollStart();
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy)
        {
            super.onScrolled(recyclerView, dx, dy);
        }
    };

    RecyclerView.ChildDrawingOrderCallback drawingOrderCallback = new RecyclerView.ChildDrawingOrderCallback()
    {
        @Override
        public int onGetChildDrawingOrder(int childCount, int i)
        {
            View focusedChild = getFocusedChild();
            int focusViewIndex = indexOfChild(focusedChild);
            if (focusViewIndex == -1)
            {
                return i;
            }
            if (focusViewIndex == i)
            {
                return childCount - 1;
            } else if (i == childCount - 1)
            {
                return focusViewIndex;
            } else
            {
                return i;
            }
        }
    };

    @Override
    public void refreshOnThemeChanged()
    {
        if (mLayoutManager.getOrientation() != OrientationHelper.HORIZONTAL)
        {
            List<ViewHolder> mAttachedScrap = getHolders("mAttachedScrap");
            List<ViewHolder> mChangedScrap = getHolders("mChangedScrap");
            List<ViewHolder> mCachedViews = getHolders("mCachedViews");
            changeTheme(mAttachedScrap);
            changeTheme(mCachedViews);
            changeTheme(mChangedScrap);
        }
    }

    private List<ViewHolder> getHolders(String name)
    {
        try
        {
            Field recyclerField = RecyclerView.class.getDeclaredField("mRecycler");
            recyclerField.setAccessible(true);
            Recycler recycler = (Recycler) recyclerField.get(this);
            Field field = Recycler.class.getDeclaredField(name);
            field.setAccessible(true);
            return (List<ViewHolder>) field.get(recycler);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        return new ArrayList<ViewHolder>();
    }

    private void changeTheme(List<ViewHolder> holders)
    {
        if (holders != null)
        {
            for (ViewHolder holder : holders)
            {
                if (holder.itemView instanceof ViewGroup)
                    changeTheme((ViewGroup) holder.itemView);
                else if (holder.itemView instanceof IThemeable)
                    ((IThemeable) holder.itemView).refreshOnThemeChanged();
            }
        }
    }

    private void changeTheme(ViewGroup vg)
    {
        if (vg instanceof IThemeable)
            ((IThemeable) vg).refreshOnThemeChanged();
        int count = vg.getChildCount();
        for (int i = 0; i < count; i++)
        {
            View v = vg.getChildAt(i);
            if (v instanceof ViewGroup)
                changeTheme((ViewGroup) v);
            else if (v instanceof IThemeable)
                ((IThemeable) v).refreshOnThemeChanged();
        }
    }

}
